type vec2 = { x: number, y: number }
/** 点 */
export interface Point {
    x: number,
    y: number
}
/** 线段 */
export interface Segment {
    start: Point, end: Point
}

export interface Line {
    x1: number,
    y1: number,
    x2: number,
    y2: number
}

export interface Rect {
    x: number,
    y: number,
    w: number,
    h: number,
}

export interface Circle {
    px: number,
    py: number,
    r: number,//半径
}

export class Vector2 {
    x = 0;
    y = 0;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    /** 加上 */
    plus(vector: Vector2) {
        return new Vector2(this.x + vector.x, this.y + vector.y);
    }

    /** 减去 */
    minus(vector: Vector2) {
        return new Vector2(this.x - vector.x, this.y - vector.y);
    }

    /** 乘法 */
    multiply(vector: Vector2) {
        return this.x * vector.x + this.y * vector.y
    }

    /** 缩放 */
    scale(k: number) {
        return new Vector2(this.x * k, this.y * k);
    }

    copy(v: Vector2) {
        this.x = v.x;
        this.y = v.y;
        return this;
    }

    clone() {
        return new Vector2(this.x, this.y);
    }

    subtract(out: Vector2, other: Vector2) {
        out.x -= other.x;
        out.y -= other.y;
        return out;
    }

    /** 长度的平方 */
    lengthSqr() {
        return this.x ** 2 + this.y ** 2;
    }


    /** 平方 */
    static absSq(v: Vector2) {
        return v.multiply(v);
    };

    /** 归一化 */
    static normalize(v: Vector2) {
        let v2 = v.scale(1 / this.abs(v));
        v2.x = v2.x
        v2.y = v2.y
        return v2
    };

    /** 绝对值 */
    static abs(v: Vector2) {
        return Math.sqrt(this.absSq(v));
    };

}

/** 角度转弧度 */
export const angelToRadian = (angle: number): number => {
    return angle / 180 * Math.PI
}

/** 弧度转角度 */
export const radianToAngle = (radian: number): number => {
    return radian * 180 / Math.PI
}

/** 向量转角度 */
export const vecToAngle = (x: number, y: number) => {
    // 使用Math.atan2()函数将向量转换为弧度值
    let radian = Math.atan2(y, x)
    // 将弧度值转换为角度值
    return radianToAngle(radian);
}

/** 两点距离的平方 */
export const distanceSqu = (px1: number, py1: number, px2: number, py2: number) => {
    const x = px1 - px2;
    const y = py1 - py2;
    return x * x + y * y
}

/** 两点间距离 */
export const distance = (px1: number, py1: number, px2: number, py2: number) => {
    return Math.sqrt(distanceSqu(px1, py1, px2, py2))
}

/** 两个点是否足够接近 */
export const twoSamePoint = (px1: number, py1: number, px2: number, py2: number) => {
    return distanceSqu(px1, py1, px2, py2) <= 4
}

/** 获取点到点方向,求方向向量 */
export const getDirByPos = (x1: number, y1: number, x2: number, y2: number) => {
    const p1 = new Vector2(x1, y1)
    const p2 = new Vector2(x2, y2)
    const { x, y } = Vector2.normalize(p1.minus(p2))
    return { dirX: x, dirY: y }
}

/** v 按照 o 为圆心 旋转 d 弧度or角度 */
export const rotate = (v: Vector2 | vec2, o: Vector2 | vec2, d: vec2 | number) => {
    const x = v.x - o.x;
    const y = v.y - o.y;
    let a = 0
    if (typeof d === 'number') {
        a = angelToRadian(d)
    } else {
        a = angelToRadian(vecToAngle(d.x, d.y))
    }
    const cos = Math.cos(a);
    const sin = Math.sin(a);
    const rx = x * cos - y * sin;
    const ry = x * sin + y * cos;
    return new Vector2(rx + o.x, ry + o.y);
}

/** 如果计算结果为0，则表明三个点共线（Collinear），函数返回0。如果结果大于0，
 * 则表示这组点组成一个逆时针方向的转折（Counter-clockwise），
 * 函数返回1。如果结果小于0，则表示这组点组成一个顺时针方向的转折（Clockwise），函数返回2。 */
const orientation = (p1: Point, p2: Point, p3: Point): number => {
    const val = (p2.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p2.x - p1.x);
    if (val === 0) {
        return 0;
    }
    return (val > 0) ? 1 : 2;
}

/** 判断两个线段是否相交 */
export const segmentsIntersect = (seg1: Segment, seg2: Segment): boolean => {
    const p1 = seg1.start;
    const q1 = seg1.end;
    const p2 = seg2.start;
    const q2 = seg2.end;

    const o1 = orientation(p1, q1, p2);
    const o2 = orientation(p1, q1, q2);
    const o3 = orientation(p2, q2, p1);
    const o4 = orientation(p2, q2, q1);

    if (o1 !== o2 && o3 !== o4) {
        return true;
    }

    return false;
}

/** 判断线段与圆是否相交 */
export const segmentsIntersectCircle = (line: Line, circle: Circle) => {

    const { x1, y1, x2, y2 } = line
    const { px, py, r } = circle
    // 计算线段的长度
    const lineLength = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));

    // 计算线段的单位向量
    const dx = (x2 - x1) / lineLength;
    const dy = (y2 - y1) / lineLength;

    // 计算圆心到线段起始点的向量
    const cx = px - x1;
    const cy = py - y1;

    // 计算圆心在线段上投影的长度
    const projection = cx * dx + cy * dy;

    // 如果投影长度小于0，则圆心在线段起点的外侧
    if (projection < 0) {
        return cx * cx + cy * cy <= r ** 2; // 检测圆与线段起点的距离是否小于半径
    }

    // 如果投影长度大于线段长度，则圆心在线段终点的外侧
    if (projection > lineLength) {
        const x = px - x2;
        const y = py - y2;
        return x * x + y * y <= r ** 2; // 检测圆与线段终点的距离是否小于半径
    }

    // 圆心在线段投影范围内，计算圆心到线段的实际距离
    const distance = cx * dy - cy * dx
    return distance ** 2 <= r ** 2; // 判断圆心到线段的距离是否小于等于半径

}